/*
ID: icerupt1
PROG: frameup
LANG: C++11
*/

/* solution
 *
 * 首先可以识别出每个矩形。将每个矩形框上经过的字符向该矩形字符连一条边，
 * 表示覆盖关系（维持了一种拓扑关系）。
 * 然后dfs，删除该点，然后从下一个入度为零的点继续遍历。
 *
*/

#include <fstream>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>

std::ifstream fin ("frameup.in" );
std::ofstream fout("frameup.out");

int const maxn = 32;
int const max_index = 26;
int const super = 26;
bool map[max_index + 2][max_index + 2];
char da[maxn][maxn];
int frames[max_index][2], left_up[max_index][2], right_down[max_index][2];
int n, m, depth;

std::vector<std::string> ans;

bool ch_in_row[maxn][max_index];
bool ch_in_col[maxn][max_index];

void init_left_up_right_down()
{
	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++) {
			if (da[i][j] == '.') continue;
			int index = da[i][j] - 'A';
			ch_in_row[i][index] = true;
			ch_in_col[j][index] = true;
		}

	for (int i = 0; i < max_index; i++) {
		int x = 0, y = 0;
		for (; x < n && !ch_in_row[x][i]; x++);
		for (; y < m && !ch_in_col[y][i]; y++);
		left_up[i][0] = x; left_up[i][1] = y;

		x = n-1; y = m-1;
		for (; x >= 0 && !ch_in_row[x][i]; x--);
		for (; y >= 0 && !ch_in_col[y][i]; y--);
		right_down[i][0] = x; right_down[i][1] = y;

		frames[i][0] = right_down[i][0] - left_up[i][0] + 1;
		frames[i][1] = right_down[i][1] - left_up[i][1] + 1;
	}
}

bool has_ch[max_index];
int in_degree[max_index];

void init_graph()
{
	for (int index = 0; index < max_index; index++) {
		if (!has_ch[index]) continue;
		map[super][index] = true;
		in_degree[index]++;

		int x = left_up[index][0], y = left_up[index][1];
		char ch = 'A' + index;
		//vertical
		for (int i = 0; i < frames[index][0]; i++) {
			int px = x + i, py = y;
			if (da[px][py] != ch)
				map[da[px][py] - 'A'][index] = true;

			py = y + frames[index][1] - 1;
			if (da[px][py] != ch)
				map[da[px][py] - 'A'][index] = true;
		}

		//horizontal
		for (int i = 0; i < frames[index][1]; i++) {
			int px = x, py = y + i;
			if (da[px][py] != ch)
				map[da[px][py] - 'A'][index] = true;

			px = x + frames[index][0] - 1;
			if (da[px][py] != ch)
				map[da[px][py] - 'A'][index] = true;
		}
	}

	for (int i = 0; i < max_index; i++)
		for (int j = 0; j < max_index; j++)
			if (map[i][j]) in_degree[j]++;
}

bool vis[max_index + 2];

void dfs(int s, int depth, std::string path)
{
	if (!depth) {
		ans.push_back(path);
		return;
	}
	vis[s] = true;
	std::vector<int> tmp;
	for (int i = 0; i < max_index; i++) {
		if (map[s][i]) {
			map[s][i] = false;
			tmp.push_back(i);
			in_degree[i]--;
		}
	}

	for (int i = 0; i < max_index; i++)
		if (has_ch[i] && !vis[i] && !in_degree[i])
			dfs(i, depth - 1, char('A' + i) + path);

	for (auto i : tmp) {
		map[s][i] = true;
		in_degree[i]++;
	}
	vis[s] = false;
}

int main()
{
	fin >> n >> m;

	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++) {
			fin >> da[i][j];
			has_ch[da[i][j] - 'A'] = true;
		}

	init_left_up_right_down();
	init_graph();

	for (int i = 0; i < max_index; i++)
		if (has_ch[i]) depth++;
	dfs(super, depth, "");

	std::sort(ans.begin(), ans.end());

	for (auto a : ans) {
		std::cout << a << '\n';
		fout << a << '\n';
	}
}

